10. Exercise: Refactor onBindViewHolder

L7 17 ViewHolders Refactor SC PART 1

In this exercise, you’ll begin refactoring the ViewHolder in the SleepNightAdapter. By encapsulating the logic in onBindViewHolder in this exercise, and onCreateViewHolder in the next exercise, you’ll create code that’s easier to maintain and enhance.

Let’s start by encapsulating the logic for binding the ViewHolder into a bind() method. When you’re done, onBindViewHolder will call holder.bind(holder,item,res).

Watch the video to see how to use Android Studio tools to do most of this refactor for you.

  1. Refactor logic in onBind() to a separate function called bind():

     private fun bind(holder: ViewHolder, item: SleepNight, res: Resources) {
        holder.sleepLength.text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, res)
        holder.quality.text = convertNumericQualityToString(item.sleepQuality, res)
        holder.qualityImage.setImageResource(when (item.sleepQuality) {
            0 -> R.drawable.ic_sleep_0
            1 -> R.drawable.ic_sleep_1
            2 -> R.drawable.ic_sleep_2
            3 -> R.drawable.ic_sleep_3
            4 -> R.drawable.ic_sleep_4
            5 -> R.drawable.ic_sleep_5
            else -> R.drawable.ic_sleep_active
        })
     }


  2. In new bind() function, convert the holder parameter to a receiver.

    Place the cursor over (but don’t select) the holder parameter. Use keyboard Option-Enter, and select Convert parameter to receiver.

    onBindViewHolder, will now call holder.*bind*(item,res).


  3. Cut the entire bind() function and paste it into the ViewHolder class, then remove its ViewHolder and private modifiers.


  4. Cut the line val res = holder.itemView.context.resources from onBindViewHolder(), and paste it into the bind() function, then remove the `res’ parameter from bind().

    Your ViewHolder class should now look like this:

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
      val res = itemView.context.resources
    
      val sleepLength: TextView = itemView.findViewById(R.id.sleep_length)
      val quality: TextView = itemView.findViewById(R.id.quality_string)
      val qualityImage: ImageView = itemView.findViewById(R.id.quality_image)
    
      fun bind(item: SleepNight) {
          sleepLength.text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, res)
          quality.text = convertNumericQualityToString(item.sleepQuality, res)
          qualityImage.setImageResource(when (item.sleepQuality) {
              0 -> R.drawable.ic_sleep_0
              1 -> R.drawable.ic_sleep_1
              2 -> R.drawable.ic_sleep_2
              3 -> R.drawable.ic_sleep_3
              4 -> R.drawable.ic_sleep_4
              5 -> R.drawable.ic_sleep_5
              else -> R.drawable.ic_sleep_active
         })
      }
    }


  5. Build and run the app and verify it runs exactly as before.

If you want to start at this step, you can download this exercise from: Step.05-Exercise-Refactor-onBindViewHolder.

You will find plenty of //TODO comments to help you complete this exercise, and if you get stuck, go back and watch the video again.

Once you’re done, you can check your solution against the solution we’ve provided here: Step.05-Solution-Refactor-onBindViewHolder, or using this git diff.

Task Description:

Complete these steps to refactor onBindViewHolder().

Task List:

Task Feedback:

Great job! In the next section you'll refactor onCreateViewHolder().